/***************************************************************************
 *   Copyright (C) 2009 by Dead_Body                                       *
 *   jamesholodnak@gmail.com                                               *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#define SCREENW	512
#define SCREENH 480

#include <stdio.h>

//use this nifty directx class
#include "dx7video.h"

extern "C" {

//for hWnd and hInstance
#include "window.h"

#include "pce/pce.h"
#include "system/system.h"
#include "gui2/gui2.h"
#include "gui2/gui2_draw.h"

//what happened to libfilters?
#include "system/sdl/scale2x/scalebit.h"
#include "system/sdl/draw/draw.h"
#include "system/sdl/interpolate/interpolate.h"
#include "system/sdl/hq2x/hq2x.h"
#include "system/sdl/hq2x/hq3x.h"

}

static CDX7Video video;
extern "C" {
int screenw,screenh,screenscale;
}
int machinew,machineh;

static u32 palette32[4096];	//increased to 4096 for pce/whatever else
static u32 *tmpscreen;
static u32 *oldscreen;

static int fullscreen;

static struct video_mode_s {
	int w,h,bpp;
	int scale;
} videomodes[] = {
	{ 640, 480,32,1},
	{ 800, 600,32,1},
	{1024, 768,32,2},
	{1280,1024,32,3},
	{0,0,0,0}
};

extern "C" void video_reinit()
{
	int bpp = 0;	//disable fullscreen mode

	if(config.windowed != 0) {
		fullscreen = 0;
		screenscale = config.windowscale;
		screenw = SCREENW * screenscale;
		screenh = SCREENH * screenscale;
		window_resize(screenw,screenh);
		log_message("resized window to %dx%d\n",screenw,screenh);
	}
	else {
		if((config.fullscreen <= 0) || (config.fullscreen > 4)) {
			log_warning("bad fullscreen video mode, setting to 640x480\n");
			config.fullscreen = 1;
		}
		fullscreen = 1;
		bpp = 32;	//32-bit fullscreen mode
		screenw = videomodes[config.fullscreen].w;
		screenh = videomodes[config.fullscreen].h;
		screenscale = videomodes[config.fullscreen].scale;
	}
	if(video.Init(hWnd,hInstance,screenw,screenh,bpp) != 0) {
		log_error("error initing dx7video");
		return;
	}
}

extern "C" void video_init()
{
	u8 pal[256 * 3];
	int i;

	for(i=0;i<256;i++) {
		pal[i*3 + 0] = palette32[i] >> 0 & 0xFF;
		pal[i*3 + 1] = palette32[i] >> 8 & 0xFF;
		pal[i*3 + 2] = palette32[i] >> 16 & 0xFF;
	}
	video_reinit();
	tmpscreen = (u32*)malloc(SCREENW*SCREENH*4*2);
	oldscreen = (u32*)malloc(SCREENW*SCREENH*4*2);
	hq2x_InitLUTs();
	hq3x_InitLUTs();
}

extern "C" void video_kill()
{
	hq2x_Kill();
	hq3x_Kill();
	if(tmpscreen)	free(tmpscreen);
	if(oldscreen)	free(oldscreen);
	tmpscreen = 0;
	oldscreen = 0;
	video.Kill();
}

extern "C" void video_setpalentry(int i,u8 r,u8 g,u8 b)
{
	palette32[i & 0xFFF] = (r << 16) | (g << 8) | (b << 0);
}

static u32 lasttime = 0;

//this handles lines coming directly from the nes engine
extern "C" void video_updateline(int line,u8 *s)
{
	int x,pitch = SCREENW;
	u32 *dest = tmpscreen;
	u8 pixel;

	//select line
	dest += pitch * line;

	//copy palette'd pixels
	for(x=0;x<256;x++)
		dest[x] = palette32[s[x]];
}

//this handles lines coming directly from the pce engine, 9bit pixels
extern "C" void video_updateline16(int line,u16 *s)
{
	int x,pitch = SCREENW;
	u32 *dest = tmpscreen;
	u16 pixel;

	//select line
	dest += pitch * line;

	//copy palette'd pixels
	for(x=0;x<512;x++)
		dest[x] = palette32[s[x] & 0x1FF];
}

extern "C" int gui_active;

static int fps;

extern "C" void video_endframe()
{
	u32 *scr,t;
	int pitch;
	static int fastforward = 0;
	static u32 frames = 0;
	static u32 time1 = 0,time2;
	static char fpsstr[256] = "";

	video.StartBlit();
	scr = (u32*)video.GetSurface();
	pitch = video.GetPitch() / 4;

	frames++;

	if(config.showinfo) {
		time2 = GetTickCount();
		if((t = time2 - time1) >= 1000) {
			fps = frames * 1000 / t;
			frames = 0;
			time1 = time2;
			sprintf(fpsstr,"%d fps",fps);
		}
		if(gui_active == 0) {
			if(pce && pce->rom) {
				char n[40];

				strncpy(n,pce->rom->name,33);
				if(strlen(pce->rom->name) > 33) {
					n[32] = n[33] = '.'; n[34] = 0;
				}
				gui_draw_text32(tmpscreen,SCREENW,GUI_TEXT,1,1,n);
			}
			gui_draw_text32(tmpscreen,SCREENW,GUI_TEXT,SCREENW-43,1,fpsstr);
		}
	}

	if(fullscreen) {
		scr += (screenw - (SCREENW * screenscale)) / 2;
		switch(config.fullscreen) {
			case 0:	//320x240
			case 1:	//640x480
			case 4:	//1280x1024
				break;
			case 2:	//800x600
			case 3:	//1024x768
				scr += 8 * pitch * 4;
				break;
		}
	}
	if(screenscale == 4) {
		draw4x(scr,pitch,tmpscreen,SCREENW,SCREENW,SCREENH);
	}
	else if(screenscale == 3) {
		if(config.filter == 0)
			draw3x(scr,pitch,tmpscreen,SCREENW,SCREENW,SCREENH);
		else if(config.filter == 1)
			scale(3,scr,pitch * 4,tmpscreen,SCREENW*4,4,SCREENW,SCREENH);
		else if(config.filter == 2)
			interpolate3x(scr,pitch,tmpscreen,SCREENW,SCREENW,SCREENH);
		else if(config.filter == 3)
		{}
	}
	else if(screenscale == 2) {
		if(config.filter == 0)
			draw2x(scr,pitch,tmpscreen,SCREENW,SCREENW,SCREENH);
		else if(config.filter == 1)
			scale(2,scr,pitch * 4,tmpscreen,SCREENW*4,4,SCREENW,SCREENH);
		else if(config.filter == 2)
			interpolate2x(scr,pitch,tmpscreen,SCREENW,SCREENW,SCREENH);
//			hq2x_32((u8*)tmpscreen,(u8*)scr,SCREENW,SCREENH,SCREENW);
	}
	else if(screenscale == 1)
		draw1x(scr,pitch,tmpscreen,SCREENW,SCREENW,SCREENH);

	if(joykeys[config.gui_keys[5]] && fastforward-- > 0)
		return;
	else
		fastforward = 10;
	t = GetTickCount();
	while((t - lasttime) < (1000 / 60)) {
		Sleep((1000 / 60) - (t - lasttime) + 0);
		t = GetTickCount();
	}
	lasttime = t;
	video.StopBlit();
}

extern "C" void video_update(u8 *s,int spitch)
{
	int x,y;
	u32 *dest = tmpscreen;

	for(y=0;y<SCREENH;y++) {
		for(x=0;x<SCREENW;x++) {
			u32 pixel = palette32[s[x]];

			if(s[x] == 0) {
				pixel = oldscreen[x + y * SCREENW];
				pixel = (pixel & 0xFF) + (pixel >> 8 & 0xFF) + (pixel >> 16 & 0xFF);
				pixel /= 5;
				pixel = (pixel << 8) | pixel;
			}
			dest[x] = pixel;
		}
		s += spitch;
		dest += SCREENW;
	}
	video_endframe();
}

extern "C" void video_copyscreen()
{
	int x,y;

	for(y=0;y<SCREENH;y++) {
		for(x=0;x<SCREENW;x++)
			oldscreen[x + y * SCREENW] = tmpscreen[x + y * SCREENW];
	}
}

extern "C" u32 video_getpixel(int x,int y)
{
	return(tmpscreen[x + y * SCREENW]);
}

extern "C" u32 video_getpalette(int idx)
{
	return(palette32[idx]);
}

extern "C" u32 *video_getscreen()
{
	return(tmpscreen);
}

extern "C" void video_togglefullscreen()
{
	config.windowed ^= 1;
	video_reinit();
}

extern "C" void video_minimize()
{
//	SDL_WM_IconifyWindow();
}

extern "C" void video_setwindowpos(int x,int y)
{
/*	SDL_SysWMinfo info;
	HWND hwnd;

	SDL_VERSION(&info.version);
	if(SDL_GetWMInfo(&info) == 0)
		return;
	hwnd = info.window;
	SetWindowPos(hwnd,0,x,y,0,0,SWP_NOSIZE);*/
}

extern "C" void video_getwindowpos(int *x,int *y)
{
/*	SDL_SysWMinfo info;
	HWND hwnd;
	RECT r;

	SDL_VERSION(&info.version);
	if(SDL_GetWMInfo(&info) == 0)
		return;
	hwnd = info.window;
	GetWindowRect(hwnd,&r);
	*x = r.left;
	*y = r.top;*/
}
